#pragma once

#include <iostream>

#include "Connection.hpp"
#include "Log.hpp"

const static int gsize = 512;

class HandlerConnection
{
public:
    HandlerConnection(handler_t process)
        :_process(process)
    {}

    // 处理读
    void HandlerRecver(Connection* conn)
    {
        errno = 0;

        while(true)
        {
            char buffer[gsize];
            ssize_t n = ::recv(conn->Sockfd(), buffer, sizeof(buffer) - 1, 0);
            if(n > 0)
            {
                buffer[n] = 0;
                conn->AppendInbuffer(buffer);
            }
            else        // 方便起见，将对端关闭连接做一起异常处理
            {
                if(errno == EWOULDBLOCK)    // 读完了
                {
                    break;
                }
                else if(errno == EINTR)     // 被信号中断，接着读
                {
                    continue;
                }
                else
                {
                    conn->_handler_excepter(conn);  // 做异常处理, 不再向下执行
                    return;
                }
            }
        }
        // 业务处理
        // 走到这里，一定是读完了
        _process(conn);
    }

    // 写与读不同，对于写来说，条件满足是缓冲区有空间了，而不是有数据了
    // 因为缓冲区刚创建出来，肯定是空的，所以可以直接写入
    // 等到条件不满足了，没空间写了，才将他设置进epoll，等待写条件满足
    // 如果写完一次之后，条件依然是满足的，就不要将他设置进epoll中进行等待
    void HandlerSender(Connection* conn)
    {
        while (true)
        {
            errno = 0;
            ssize_t n = ::send(conn->Sockfd(), conn->Outbuffer().c_str(), conn->Outbuffer().size(), 0);
            if(n > 0)
            {
                conn->DiscardOutbuffer(n);
                if(conn->Outbuffer().empty())   // 发送完了
                {
                    break;
                }
            }
            else if(n == 0)
            {
                break;
            }
            else    // n < 0 可能是发送条件不满足，缓冲区满了
            {
                if(errno == EWOULDBLOCK)      // 发送条件不满足
                {
                    break;
                }
                else if(errno == EINTR)       // 信号中断，重发
                {
                    continue;
                }
                else                          // 异常处理
                {
                    conn->_handler_excepter(conn);
                    return;
                }
            }
        }
        
        // 到这里，有两种情况
        // 1. 发完了，缓冲区还有空间，发送条件依然满足
        // 2. 每发完，缓冲区没有空间了，发送条件不满足
        if(!conn->Outbuffer().empty())  // 不空
        {
            conn->_R->EnableConnectionReadWrite(conn->Sockfd(), true, true);
        }   
        else
        {
            conn->_R->EnableConnectionReadWrite(conn->Sockfd(), true, false);
        }
    }

    void HandlerExcepter(Connection* conn)
    {
        // 对于异常，直接删除连接
        conn->_R->DelConnection(conn->Sockfd());
    }
private:
    handler_t _process;
};